package com.xd;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ZkClient {

    /**
     * 注意：
     *  1、使用zookeeper的前提是在linux的，/ect/hosts 中配置了ip地址映射，否则要用ip地址
     *  2、中间逗号分割，不能有空格，否则会连接不上zookeeper集群
     */
    private String connectString = "zookeeper1:2181,zookeeper2:2181,zookeeper3:2181";

    //毫秒，若发生org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss异常，提高该参数
    private int sessionTimeout = 20000000;

    private ZooKeeper zkClient;

    @BeforeEach
    public void init() throws IOException {

        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                /*监听器的回调函数，由于只能监听一次（因为监听一次后要重写监听），为了
                   能继续监听，则再回调函数中再次注册监听器
                   该回调函数的执行时机是：每监听完一次后执行，然后接着监听
                 */
                System.out.println("zkClient的回调方法执行");

                System.out.println("----------------------------------");
                List<String> children = null;
                try {
                    children = zkClient.getChildren("/sanguo", true);

                    for (String child : children) {
                        System.out.println(child);
                    }

                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("----------------------------------");
            }
        });
    }

    /**
     * 创建节点
     */
    @Test
    public void create() throws InterruptedException, KeeperException {
        String nodeCreated = zkClient.create("/sanguo/shuguo", "liubei".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 监听节点的路径变化
     */
    @Test
    public void getChildren() throws InterruptedException, KeeperException {

        //监听器的入口，注册监听器，由于这里为true，执行结束后会执行zkClient监听器的回调函数再次监听
        List<String> children = zkClient.getChildren("/sanguo", true);
        for (String child : children) {
            System.out.println(child);
        }

        //延时，目的是保证监听器线程一直存在
        Thread.sleep(Long.MAX_VALUE);
    }

    /**
     * 判断某个节点是否存在
     */
    @Test
    public void exist() throws InterruptedException, KeeperException {
        //不注册监听器，但还是会执行zkClient的回调方法，因为调的是zkClient的方法
        Stat exists = zkClient.exists("/sanguo/weiguo", false);
        System.out.println(exists == null ? "no exist" : "exist");
    }

}
